home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / winterp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-28  |  53.3 KB  |  1,379 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         winterp.c
  5. * RCS:          $Header: winterp.c,v 1.13 91/04/17 19:44:34 mayer Exp $
  6. * Description:  WINTERP main() file.
  7. * Author:       Niels Mayer, HPLabs
  8. * Created:      Sat Jun 10 02:15:35 1989
  9. * Modified:     Thu Nov 21 22:20:26 1991
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: winterp.c,v 1.13 91/04/17 19:44:34 mayer Exp $";
  42.  
  43. #include <stdio.h>
  44. #ifdef __STRICT_BSD__        /* for NeXT... */
  45. extern char *getenv();
  46. #else
  47. #include <stdlib.h>        /* for unlink(), getenv(), etc */
  48. #endif /* __STRICT_BSD__ */
  49.  
  50. #include <ctype.h>
  51.  
  52. #include "../src-server/config.h" /* define DEFAULT_UNIX_SOCKET_FILEPATH DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR, etc */
  53.  
  54. #if (defined(WINTERP_WANT_INET_SERVER) || defined(WINTERP_WANT_UNIX_SERVER))
  55. #include <sys/types.h>
  56. #include <sys/socket.h>
  57. #endif                /* (defined(WINTERP_WANT_INET_SERVER) || defined(WINTERP_WANT_UNIX_SERVER)) */
  58.  
  59. #ifdef WINTERP_WANT_INET_SERVER
  60. #include <netinet/in.h>
  61. #include <netdb.h>
  62. #endif                /* WINTERP_WANT_INET_SERVER */
  63.  
  64. #ifdef WINTERP_WANT_UNIX_SERVER
  65. #include <sys/un.h> /* for AF_UNIX sockets */
  66. #endif                /* WINTERP_WANT_UNIX_SERVER */
  67.  
  68. #include <X11/Intrinsic.h>
  69. #include <X11/Shell.h>
  70. #include <Xm/Xm.h>
  71.  
  72. #include "winterp.h"
  73.  
  74. /* this must come after winterp.h since WINTERP_MOTIF_11 may be def'd there */
  75. #ifdef WINTERP_MOTIF_11
  76. #include <Xm/Protocols.h>    /* <Xm/Protocols.h> location seems to have moved in 1.1 */
  77. #else
  78. #include <X11/Protocols.h>
  79. #endif                /* WINTERP_MOTIF_11 */
  80.  
  81. #include "user_prefs.h"
  82. #include "xlisp/xlisp.h"
  83.  
  84.  
  85. /* forward declarations */
  86. static void Read_Eval_Print();
  87. static int  Read_From_Stream_Eval_And_Print();
  88. #ifdef WINTERP_WANT_INET_SERVER
  89. static void AF_INET_Read_Eval_Print();
  90. static int  Initialize_AF_INET_Server_Socket();
  91. #endif                /* WINTERP_WANT_INET_SERVER */
  92. #ifdef WINTERP_WANT_UNIX_SERVER
  93. static void AF_UNIX_Read_Eval_Print();
  94. static int  Initialize_AF_UNIX_Server_Socket();
  95. #endif                /* WINTERP_WANT_UNIX_SERVER */
  96. static void Winterp_Xtoolkit_Error_Handler();
  97. static void Winterp_Xtoolkit_Warning_Handler();
  98. static int  Winterp_Xlib_Error_Handler();
  99. void        Winterp_Application_Shell_WMDelete_Callback();
  100.  
  101. /* global variables */
  102. jmp_buf        top_level;
  103. CONTEXT        cntxt;
  104. int        read_eval_print_just_called;
  105. int        lisp_reader_hit_eof;
  106. char*        app_name = NULL;
  107. char*        app_class = NULL;
  108. #ifdef WINTERP_WANT_INET_SERVER
  109. static int    client_AF_INET_listen_socket = NULL;
  110. #endif                /* WINTERP_WANT_INET_SERVER */
  111. #ifdef WINTERP_WANT_UNIX_SERVER
  112. static int    client_AF_UNIX_listen_socket = NULL;
  113. #endif                /* WINTERP_WANT_UNIX_SERVER */
  114. Widget        toplevel_Wgt = NULL;
  115. XtAppContext    app_context = NULL;
  116. Display*    display;
  117. Window        root_win;
  118. Screen*        screen;
  119. Colormap    colormap;
  120. Atom        wm_delete_atom;
  121. Pixel        default_foreground_pixel, default_background_pixel;
  122. USER_PREFS_DATA user_prefs;    /* extern declared in user_prefs.h, really here */
  123. char        temptext[BUFSIZ]; /* a temporary text buffer, for sprintf() */
  124. Arg        _args[10];    /* for XtSetArg() macros in winterp.h */
  125. int        _num_args;    /* for XtSetArg() macros in winterp.h */
  126.  
  127. /* 
  128.  * Data on how user-customization resources are interpreted:
  129.  * this must be kept up to date with data structure USER_PREFS_DATA_PTR 
  130.  * in user_prefs.h
  131.  */
  132. static XtResource resources[] = {
  133.   /*
  134.    * The name of the file to load to initialize xlisp.
  135.    */
  136.   {"lispInitFile", "LispInitFile",
  137.      XmRString, sizeof(String),
  138.      XtOffset(USER_PREFS_DATA_PTR, lisp_init_file),
  139.      XmRString, (XtPointer) DEFAULT_LISP_INIT_FILE},
  140.  
  141.   /*
  142.    * The name of the file to output lisp transactions.
  143.    */
  144.   {"lispTranscriptFile", "LispTranscriptFile",
  145.      XmRString, sizeof(String),
  146.      XtOffset(USER_PREFS_DATA_PTR, lisp_transcript_file),
  147.      XmRString, (XtPointer) DEFAULT_LISP_TRANSCRIPT_FILE},
  148.  
  149.   /*
  150.    * The name of the default directory for 'load'. This is only
  151.    * used in cases where 'load' wasn't supplied a full
  152.    * filepath (i.e. a path beginning with '/' or '.').
  153.    *
  154.    * Note that "lispLibDir" should be the path to an existing directory with
  155.    * a trailing '/', e.g. "/usr/local/winterp/lisp-lib/". The default is
  156.    * "./" so as to simulate Xlisp's default load behavior.
  157.    * (See also w_utils.c:Wut_Prim_LOAD()).
  158.    */
  159.   {"lispLibDir", "LisplibDir",
  160.      XmRString, sizeof(String),
  161.      XtOffset(USER_PREFS_DATA_PTR, lisp_lib_dir),
  162.      XmRString, (XtPointer) DEFAULT_LISP_LIB_DIR},
  163.   
  164.   /*
  165.    * Setting this boolean to FALSE will allow WINTERP to startup
  166.    * without printing lots of output.
  167.    */
  168.   {"enableInitMsgs", "EnableInitMsgs",
  169.      XmRBoolean, sizeof(Boolean),
  170.      XtOffset(USER_PREFS_DATA_PTR, enable_init_msgs),
  171.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_INIT_MSGS},
  172.  
  173. #ifdef WINTERP_WANT_INET_SERVER
  174.   /*
  175.    * The port number of the widget interpreter lisp server.
  176.    */
  177.   {"servicePort", "ServicePort",
  178.      XmRInt, sizeof(int),
  179.      XtOffset(USER_PREFS_DATA_PTR, service_port),
  180.      XmRImmediate, (XtPointer) DEFAULT_INET_SERVICE_PORT},
  181.  
  182.   /*
  183.    * The service name of the widget interpreter lisp server.
  184.    */
  185.   {"serviceName", "ServiceName",
  186.      XmRString, sizeof(String),
  187.      XtOffset(USER_PREFS_DATA_PTR, service_name),
  188.      XmRString, (XtPointer) DEFAULT_INET_SERVICE_NAME},
  189.  
  190.   /*
  191.    * Setting this boolean to TRUE will start up WINTERP so that
  192.    * it will accept input from its INET Domain Server. Those worried about
  193.    * security when running winterp-based applications will want to
  194.    * set this to FALSE in the application defaults file for the application.
  195.    */
  196.   {"enableInetServer", "enableInetServer",
  197.      XmRBoolean, sizeof(Boolean),
  198.      XtOffset(USER_PREFS_DATA_PTR, enable_AF_INET_server),
  199.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_INET_SERVER},
  200. #endif                /* WINTERP_WANT_INET_SERVER */
  201.  
  202. #ifdef WINTERP_WANT_UNIX_SERVER
  203.   /*
  204.    * Setting this boolean to FALSE will start up WINTERP without
  205.    * it's Unix Domain server. Those worried about security when running
  206.    * winterp-based applications on a multi-user machine will want
  207.    * to set this in the  application defaults file for the application.
  208.    */
  209.   {"enableUnixServer", "enableUnixServer",
  210.      XmRBoolean, sizeof(Boolean),
  211.      XtOffset(USER_PREFS_DATA_PTR, enable_AF_UNIX_server),
  212.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_UNIX_SERVER},
  213.  
  214.   /*
  215.    * This is set to the full pathname for the AF_UNIX domain socket-file
  216.    */
  217.   {"unixSocketFilepath", "UnixSocketFilepath",
  218.      XmRString, sizeof(String),
  219.      XtOffset(USER_PREFS_DATA_PTR, unix_socket_filepath),
  220.      XmRString, (XtPointer) DEFAULT_UNIX_SOCKET_FILEPATH},
  221. #endif                /* WINTERP_WANT_UNIX_SERVER */
  222.  
  223.   /*
  224.    * Setting this boolean to FALSE will start up WINTERP
  225.    * with the Xtoolkit's default XtError handler -- any XtErrors
  226.    * will cause WINTERP to exit. By default, this is TRUE,
  227.    * which means that a lisp error will be signalled, and the
  228.    * call-sequence (or callback) that caused the error will
  229.    * terminate, however WINTERP will be able to execute other callbacks,
  230.    * input from the XLISP eval-server, etc. For interactive
  231.    * use, I suggest leaving this resource at the default TRUE;
  232.    * for delivered applications, you probably want to set this to
  233.    * FALSE.
  234.    */
  235.   {"enableXtErrorBreak", "EnableXtErrorBreak",
  236.      XmRBoolean, sizeof(Boolean),
  237.      XtOffset(USER_PREFS_DATA_PTR, enable_XtError_break),
  238.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_XT_ERROR_BREAK},
  239.  
  240.   /*
  241.    * Setting this boolean to FALSE will start up WINTERP
  242.    * with the Xtoolkit's default XtWarning handler -- any XtWarnings
  243.    * will just cause a message to be printed, execution will continue.
  244.    * By default, this is FALSE which means that a warning message will get
  245.    * printed, but Lisp will not break. This is set to FALSE by default
  246.    * because some XtWarnings were not meant to be broken out of and can
  247.    * leave Motif in a weird state, causing possible subsequent core-dumps.
  248.    * If you know don't know what you're doing I suggest leaving this
  249.    * resource at the default FALSE value.
  250.    */
  251.   {"enableXtWarningBreak", "EnableXtWarningBreak",
  252.      XmRBoolean, sizeof(Boolean),
  253.      XtOffset(USER_PREFS_DATA_PTR, enable_XtWarning_break),
  254.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_XT_WARNING_BREAK},
  255.  
  256.   /*
  257.    * Setting this boolean to FALSE will start up WINTERP
  258.    * with the Xlib's default Error handler -- any XErrors
  259.    * will cause WINTERP to exit. By default, this is TRUE,
  260.    * which means that a lisp error will be signalled, and the
  261.    * call-sequence (or callback) that caused the error will
  262.    * terminate, however WINTERP will be able to execute other callbacks,
  263.    * input from the XLISP eval-server, etc. For interactive
  264.    * use, I suggest leaving this resource at the default TRUE;
  265.    * for delivered applications, you probably want to set this to
  266.    * FALSE.
  267.    */
  268.   {"enableXErrorBreak", "EnableXErrorBreak",
  269.      XmRBoolean, sizeof(Boolean),
  270.      XtOffset(USER_PREFS_DATA_PTR, enable_XError_break),
  271.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_X_ERROR_BREAK}
  272. };
  273.  
  274. /*
  275.  * Table indicating how to set-from-the-command-line the application-specific
  276.  * resources specified in resources[] above.
  277.  */
  278. static XrmOptionDescRec commandline_options_table[] = {
  279.   {"-init_file",    ".lispInitFile",    XrmoptionSepArg, NULL},
  280.   {"-transcript_file",    ".lispTranscriptFile",    XrmoptionSepArg, NULL},
  281.   {"-lib_dir",        ".lispLibDir",        XrmoptionSepArg, NULL},
  282.   {"-no_init_msgs",    ".enableInitMsgs",    XrmoptionNoArg, "false"},
  283.   {"-enable_init_msgs",    ".enableInitMsgs",    XrmoptionNoArg, "true"},
  284. #ifdef WINTERP_WANT_INET_SERVER
  285.   {"-serv_port",    ".servicePort",        XrmoptionSepArg, NULL},
  286.   {"-serv_name",    ".serviceName",        XrmoptionSepArg, NULL},
  287.   {"-no_inet_server",    ".enableInetServer",    XrmoptionNoArg, "false"},
  288.   {"-enable_inet_server",".enableInetServer",    XrmoptionNoArg, "true"},
  289. #endif                /* WINTERP_WANT_INET_SERVER */
  290. #ifdef WINTERP_WANT_UNIX_SERVER
  291.   {"-no_unix_server",    ".enableUnixServer",    XrmoptionNoArg, "false"},
  292.   {"-enable_unix_server",".enableUnixServer",    XrmoptionNoArg, "true"},
  293.   {"-unix_socket_file",    ".unixSocketFilepath",    XrmoptionSepArg, NULL},
  294. #endif                /* WINTERP_WANT_UNIX_SERVER */
  295.   {"-no_xterr_brk",    ".enableXtErrorBreak",    XrmoptionNoArg, "false"},
  296.   {"-enable_xterr_brk",    ".enableXtErrorBreak",    XrmoptionNoArg, "true"},
  297.   {"-no_xtwarn_brk",    ".enableXtWarningBreak",XrmoptionNoArg, "false"},
  298.   {"-enable_xtwarn_brk",".enableXtWarningBreak",XrmoptionNoArg, "true"},
  299.   {"-no_xerr_brk",    ".enableXErrorBreak",    XrmoptionNoArg, "false"},
  300.   {"-enable_xerr_brk",    ".enableXErrorBreak",    XrmoptionNoArg, "true"}
  301. };
  302.  
  303. /*
  304.  * Setup an action table for winterp. Note that action procedure "Lisp"
  305.  * is a special action procedure that calls the lisp evaluator on the
  306.  * parameters of the action. A translation like
  307.  * "Ctrl<Key>K: Lisp(quack 1 2 3)" will evaluate '(quack 1 2 3)'
  308.  */
  309. extern void Wtx_Winterp_Lisp_Action_Proc(); /* w_txlations.c */
  310. static XtActionsRec winterp_action_table[] = {
  311.   {"Lisp", Wtx_Winterp_Lisp_Action_Proc}
  312. };
  313.  
  314.  
  315. /*******************************************************************************
  316.  * main - the main routine
  317.  ******************************************************************************/
  318. main(argc,argv)
  319.   int argc; char *argv[];
  320. {
  321.   extern LVAL true;        /* from xlisp/xlglob.c */
  322.   extern LVAL s_evalhook,s_applyhook; /* from xlisp/xlglob.c */
  323.   extern FILE* osaopen();    /* from xlisp/unixstuff.c */
  324.   extern FILE *tfp;        /* from xlisp/xlglob.c */
  325.   extern int xldebug;        /* from xlisp/xlglob.c */
  326.   extern int xltrcindent;    /* from xlisp/xlglob.c */
  327.   extern LVAL Wshl_WidgetID_To_WIDGETOBJ(); /* wc_SHELL.c */
  328.   extern void Wfu_Sanity_Check(); /* w_funtab.c */
  329.   char** original_argv;
  330.   int    original_argc;
  331.   XEvent event;
  332.  
  333.  
  334.   /*
  335.    * Trim directory path off of program name.
  336.    */
  337.   if ((app_name = rindex(argv[0], '/')) == NULL)
  338.     app_name = argv[0];
  339.   else
  340.     app_name++;
  341.  
  342.   /*
  343.    * Trim "Login Shell" from the program name
  344.    */
  345.   if (*app_name == '-')
  346.     app_name++;
  347.  
  348.   /*
  349.    * sanity check to ensure that the number of pointers to funtab entries in
  350.    * w_funtab.h correspond to the number of entries in w_funtab.c:funtab[].
  351.    */
  352.   Wfu_Funtab_Sanity_Check();
  353.  
  354.   /* 
  355.    * Make a copy of argv,argc to pass into
  356.    * 'toplevel_Wgt = XtAppCreateShell(...applicationShellWidgetClass...)'
  357.    * This is used by session managers so as to provide arguments to restart
  358.    * the application with the same arguments as the current invocation.
  359.    * We must make a copy here because XtOpenDisplay() modifies argv and argc
  360.    * and we twiddle argc/argv below.
  361.    */
  362.   original_argv = (char**) XtMalloc((unsigned) (argc + 1) * sizeof(char*));
  363.   for (original_argc = 0 ; original_argc < argc ; original_argc++)
  364.     original_argv[original_argc] = argv[original_argc];
  365.   original_argv[original_argc] = NULL;
  366.   
  367.   /*
  368.    * Special case the first argument on the command line... 
  369.    * If it is "-class <classname>", then use the next argument <classname> as the
  370.    * application class.  This kludge allows us to run winterp using a variable
  371.    * application class name, thus allowing us to use specify variable APP-DEFAULT
  372.    * files. (Hack submitted by Eric Blossom of HP Western Response Center Labs.)
  373.    */
  374.   app_class = "Winterp";
  375.   if ((argc >= 3) && (strcmp(argv[1], "-class") == 0)) {
  376.     app_class = argv[2];
  377.     argv[2] = argv[0];
  378.     argv += 2;
  379.     argc -= 2;
  380.   }
  381.  
  382.   /* 
  383.    * Initialize the toolkit
  384.    */
  385.   XtToolkitInitialize();
  386.  
  387.   /* 
  388.    * Initialize Resource converters: normally, these functions are called 
  389.    * from XtCreateWidget(), XtCreateManagedWidget(),  XtCreatePopupShell(), and
  390.    * XtAppCreateShell(); they only get called the first time you create a
  391.    * widget of class Primitive or Manager because they're called from the 
  392.    * ClassInitialize() procedure. With the way WINTERP's automatic resource
  393.    * converters work, you can end up asking for a resource conversion to occur
  394.    * before any ClassInitialize() procs are called, and that would cause errors
  395.    * like "X Toolkit Warning: No type converter registered for 'String' to ..."
  396.    */
  397.   XmRegisterConverters();    /* from Xm/ResConvert.c -- used in Manager, Primitive and Vendor ClassInitialize() */
  398.   _XmRegisterPixmapConverters(); /* from Xm/Visual.c -- used in Manager, Primitive and Vendor ClassInitialize() */
  399.  
  400.   /*
  401.    * Sanity check to ensure that the version of the Motif toolkit libraries
  402.    * used correspond to the Motif toolkit header <Xm/Xm.h>. This test is only valid
  403.    * after XmRegisterConverters() has been called.
  404.    */
  405.   if (xmUseVersion != XmVersion) { /* XmVersion def'd and xmUseVersion externed in <Xm/Xm.h> */
  406.     (void) fprintf(stderr, "%s: Fatal error: application must be recompiled with <Xm/Xm.h> matching libXm.a\n", app_name);
  407.     (void) fprintf(stderr, "\t\t(header version == %d, library version == %d)\n", XmVersion, xmUseVersion);
  408.     exit(1);
  409.   }
  410.  
  411.   app_context = XtCreateApplicationContext();
  412.   display = XtOpenDisplay(app_context, (String) NULL, app_name, app_class,
  413.               commandline_options_table, XtNumber(commandline_options_table),
  414.               &argc, argv);
  415.   if (!display)
  416.     xlfatal("Can't open display -- XtOpenDisplay() failed.");
  417.  
  418.   if (argc > 1) {        /* if argc!=0, then there are invalid arguments that didn't get parsed by XtOpenDisplay() */
  419.     (void) fprintf (stderr, "usage: %s [-class <classname>] [-init_file <file.lsp>]\n", app_name);
  420.     (void) fprintf (stderr, "\t[-transcript_file <file.out>] [-lib_dir <path-to-load-dir>]\n");
  421.     (void) fprintf (stderr, "\t[-no_init_msgs] [-enable_init_msgs]\n");
  422. #ifdef WINTERP_WANT_INET_SERVER
  423.     (void) fprintf (stderr, "\t[-serv_port <portnum>] [-serv_name <servname>]\n");
  424.     (void) fprintf (stderr, "\t[-no_inet_server] [-enable_inet_server]\n");
  425. #endif                /* WINTERP_WANT_INET_SERVER */
  426. #ifdef WINTERP_WANT_UNIX_SERVER
  427.     (void) fprintf (stderr, "\t[-no_unix_server] [-enable_unix_server]\n");
  428.     (void) fprintf (stderr, "\t[-unix_socket_file <socket-filepath>]\n");
  429. #endif                /* WINTERP_WANT_UNIX_SERVER */
  430.     (void) fprintf (stderr, "\t[-no_xterr_brk] [-enable_xterr_brk]\n");
  431.     (void) fprintf (stderr, "\t[-no_xtwarn_brk] [-enable_xtwarn_brk]\n");
  432.     (void) fprintf (stderr, "\t[-no_xerr_brk] [-enable_xerr_brk]\n");
  433.     (void) fprintf (stderr, "\t[... Xtoolkit options ...]\n");
  434.     (void) fprintf (stderr, "\tNote: if you wish to use the -class option it must be the\n");
  435.     (void) fprintf (stderr, "\tfirst argument following %s.\n", app_name);
  436.     xlfatal("Invalid command-line arguments.");
  437.   }
  438.  
  439.   /* 
  440.    * Set close-on-exec on file descriptor of display connection. Otherwise, any
  441.    * child processes started up by WINTERP will inherit the file-descriptor, and
  442.    * windows will not disappear after WINTERP is killed while child processes remain.
  443.    */
  444.   fcntl(ConnectionNumber(display), F_SETFD, 1);
  445.  
  446.   /*
  447.    * initialize some global variables used throughout this program.
  448.    * NOTE: if winterp ever gets changed to use application contexts enabling
  449.    * multiple displays, screens, etc, then we'll have to make some major changes
  450.    * here, and to any primitives that use these values.
  451.    */
  452.   root_win = DefaultRootWindow(display);
  453.   screen = DefaultScreenOfDisplay(display);
  454.   colormap = XDefaultColormapOfScreen(screen);
  455.   wm_delete_atom = XmInternAtom(display, "WM_DELETE_WINDOW", FALSE);
  456.  
  457.   /*
  458.    * Setup action table for accelerators and translations.
  459.    */
  460.   XtAppAddActions(app_context, winterp_action_table, XtNumber(winterp_action_table));
  461.   
  462.   /* 
  463.    * We need toplevel_Wgt so that we can have around a "default" set of X
  464.    * structures (colors, graphics contexts etc) for use by XtConvert()...
  465.    * this is a kludge. We also need this widget around in order to set
  466.    * Winterp-specific application resources in structure user_prefs.
  467.    *
  468.    * So as not to bother people with an uneccesary window, we create the
  469.    * window at location +1+1, then unmap it.
  470.    */
  471.   ARGLIST_RESET();
  472.   ARGLIST_ADD(XmNdeleteResponse, XmDO_NOTHING);    /* we handle wm deletion (f.kill) w/ XmAddWMProtocolCallback() below. */
  473.   ARGLIST_ADD(XmNscreen, (XtArgVal) screen);
  474.   ARGLIST_ADD(XmNargc, (XtArgVal) original_argc);
  475.   ARGLIST_ADD(XmNargv, (XtArgVal) original_argv);
  476.   ARGLIST_ADD(XmNgeometry, (XtArgVal) "10x10+1+1"); /* we don't want user to have to place this window, so give it a location; giving size prevents "Error: Shell widget winterp has zero width and/or height" */
  477.   toplevel_Wgt = XtAppCreateShell(app_name, app_class, applicationShellWidgetClass, display, ARGLIST());
  478.   XmAddWMProtocolCallback(toplevel_Wgt, wm_delete_atom, Winterp_Application_Shell_WMDelete_Callback, NULL);
  479.   XtGetApplicationResources(toplevel_Wgt, &user_prefs, resources, XtNumber(resources), NULL, 0); /* place application resources in user_prefs global struct. */
  480.   XtRealizeWidget(toplevel_Wgt); /* give the order to create the windows, etc. */
  481.   XmUpdateDisplay(toplevel_Wgt); /* after this executes, the widget will get realized, windows created, etc. */
  482.   XtUnmapWidget(toplevel_Wgt);    /* once the windows are created by XtRealizeWidget()/XmUpdateDisplay(), we may hide the window by unmapping */
  483.   XtFree((char*) original_argv); /* Motif makes a copy of this upon setting XmNargv resource however, if this is placed after XtAppCreateShell() call, you get a coredump... */
  484.  
  485.   /*
  486.    * Get Xtoolkit's default foreground and background Pixels, set globals
  487.    * to these values.
  488.    */
  489.   {
  490.     XrmValue from, to;
  491.  
  492.     from.size = (unsigned int) strlen(XtDefaultForeground) + 1;
  493.     from.addr = (XtPointer) XtDefaultForeground;
  494.     to.size = (unsigned int) sizeof(Pixel);
  495.     to.addr = (XtPointer) &default_foreground_pixel;
  496.     XtConvert(toplevel_Wgt, XmRString, &from, XmRPixel, &to);
  497.     if (to.addr == NULL)    /* error if conversion failed */
  498.       xlfatal("XtConvert() couldn't convert XtDefaultForeground to XmRPixel.");
  499.  
  500.     from.size = (unsigned int) strlen(XtDefaultBackground) + 1;
  501.     from.addr = (XtPointer) XtDefaultBackground;
  502.     to.size = (unsigned int) sizeof(Pixel);
  503.     to.addr = (XtPointer) &default_background_pixel;
  504.     XtConvert(toplevel_Wgt, XmRString, &from, XmRPixel, &to);
  505.     if (to.addr == NULL)    /* error if conversion failed */
  506.       xlfatal("XtConvert() couldn't convert XtDefaultBackground to XmRPixel.");
  507.   }
  508.  
  509. #ifdef WINTERP_WANT_INET_SERVER
  510.   if (user_prefs.enable_AF_INET_server) {
  511.     /*
  512.      * get a socket to listen on. when it's selected, call AF_INET_Read_Eval_Print()
  513.      * to open a connection socket, process the client request, and close the socket
  514.      */
  515.     client_AF_INET_listen_socket = Initialize_AF_INET_Server_Socket();
  516.     (void) XtAppAddInput(app_context, client_AF_INET_listen_socket, XtInputReadMask,
  517.              AF_INET_Read_Eval_Print, NULL);
  518.   }
  519. #endif                /* WINTERP_WANT_INET_SERVER */
  520.  
  521. #ifdef WINTERP_WANT_UNIX_SERVER
  522.   if (user_prefs.enable_AF_UNIX_server) {
  523.     /*
  524.      * get a socket to listen on. when it's selected, call AF_UNIX_Read_Eval_Print()
  525.      * to open a connection socket, process the client request, and close the socket
  526.      */
  527.     client_AF_UNIX_listen_socket = Initialize_AF_UNIX_Server_Socket();
  528.     (void) XtAppAddInput(app_context, client_AF_UNIX_listen_socket, XtInputReadMask,
  529.              AF_UNIX_Read_Eval_Print, NULL);
  530.   }
  531. #endif                /* WINTERP_WANT_UNIX_SERVER */
  532.  
  533.  
  534.   /*
  535.    * Setup Xlib and Xtoolkit warning and error handlers so that errors inside
  536.    * the Xtoolkit will call xlerror().
  537.    */
  538.   if (user_prefs.enable_XtError_break)
  539.     (void) XtAppSetErrorHandler(app_context, Winterp_Xtoolkit_Error_Handler);
  540.   if (user_prefs.enable_XtWarning_break)
  541.     (void) XtAppSetWarningHandler(app_context, Winterp_Xtoolkit_Warning_Handler);
  542.   if (user_prefs.enable_XError_break)
  543.     XSetErrorHandler(Winterp_Xlib_Error_Handler);
  544.  
  545.   if (user_prefs.enable_init_msgs) {
  546.     (void) printf("================================================================================\n");
  547. #ifdef WINTERP_MOTIF_113
  548.     (void) printf("WINTERP -- Motif 1.1.3 Widget INTERPreter\n");
  549. #else /* !defined(WINTERP_MOTIF_113) */
  550. #ifdef WINTERP_MOTIF_111
  551.     (void) printf("WINTERP -- Motif 1.1.1 Widget INTERPreter\n");
  552. #else /* !defined(WINTERP_MOTIF_111) --> Plain old 1.0 or 1.1 */
  553.     (void) printf("WINTERP -- Motif %d.%d Widget INTERPreter\n", XmVERSION, XmREVISION); /* from <Xm/Xm.h> */
  554. #endif /* WINTERP_MOTIF_111 */
  555. #endif /* WINTERP_MOTIF_113 */
  556.     (void) printf("\tby Niels P. Mayer (mayer@hplabs.hp.com).\n");
  557.     (void) printf("\tWINTERP version %d.%d, Copyright (c) 1989-1991 Hewlett-Packard Company\n",
  558.           WINTERP_VERSION_INT, WINTERP_REVISION_INT); /* from winterp.h */
  559.     (void) printf("\tXLISP version %d.%d, Copyright (c) 1985-1989, by David Betz\n\n",
  560.           XLISP_VERSION_INT, XLISP_REVISION_INT); /* from xlisp/xlisp.h */
  561.   }
  562.  
  563.   /* 
  564.    * Startup XLISP
  565.    */
  566.   if (user_prefs.enable_init_msgs)
  567.     osinit("Initializing ...\n");
  568.   else 
  569.     osinit("");
  570.  
  571.   /* setup initialization error handler */
  572.   xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, (LVAL)1);
  573.   if (setjmp(cntxt.c_jmpbuf))
  574.     xlfatal("Fatal XLISP initialization error.");
  575.   if (setjmp(top_level))
  576.     xlfatal("XLISP RESTORE not allowed during initialization.");
  577.  
  578.   /* initialize xlisp */
  579.   xlinit();            /* xlisp/xlinit.c */
  580.  
  581.   /* initialize WINTERP modules */
  582.   Wso_Init();            /* w_savedobjs.c */
  583.   Wres_Init();            /* w_resources.c */
  584.   Wxms_Init();            /* w_XmString.c */
  585.   Wcb_Init();            /* w_callbacks.c */
  586.   Wto_Init();            /* w_timeouts.c */
  587.   Wtx_Init();            /* w_txlations.c */
  588.   Weh_Init();            /* w_evnthndlr.c */
  589.   Wxm_Init();            /* w_libXm.c */
  590.  
  591.   /* 
  592.    * The following create interfaces to all the motif widget-classes via
  593.    * xlisp classes, by calling Wcls_Create_Subclass_Of_WIDGET_CLASS()
  594.    * with o_WIDGET_CLASS (def'd in Wc_WIDGET_Init()) as their superclass.
  595.    * Methods on the specific widget classes correspond to 
  596.    * special operations pertaining to that class, and not to others. 
  597.    * These derived classes may override the 'Widget_Class' :isnew method 
  598.    * for cases where motif "convenience" functions are used to create the 
  599.    * widget. Additionally, since different classes generate different callback
  600.    * structures, certain widgetclasses may override the metaclass' :set_callback
  601.    * and :add_callback methods so as to allow dereferencing of the appropriate
  602.    * callback structure elements.
  603.    */
  604.   Wc_WIDGET_Init();        /* WIDGET_CLASS metaclass */
  605.   Wc_SHELL_Init();        /* SHELL and POPUP_SHELL metaclasses */
  606.   Wc_ArrowB_Init();
  607.   Wc_BulletinB_Init();
  608.   Wc_CascadeB_Init();
  609.   Wc_Command_Init();
  610.   Wc_DrawingA_Init();
  611.   Wc_DrawnB_Init();
  612.   Wc_FileSB_Init();
  613.   Wc_Form_Init();
  614.   Wc_Frame_Init();
  615.   Wc_Label_Init();
  616.   Wc_List_Init();
  617.   Wc_MainW_Init();
  618.   Wc_MessageB_Init();
  619.   Wc_PanewW_Init();
  620.   Wc_PushB_Init();
  621.   Wc_RowColumn_Init();
  622.   Wc_Scale_Init();
  623.   Wc_ScrollBar_Init();
  624.   Wc_ScrolledW_Init();
  625.   Wc_SelectioB_Init();
  626.   Wc_Separator_Init();
  627.   Wc_Text_Init();
  628.   Wc_ToggleB_Init();
  629. #ifdef HP_GRAPH_WIDGET
  630.   Wc_XmGraph_Init();
  631. #endif                /* HP_GRAPH_WIDGET */
  632.  
  633.   {
  634.     LVAL sym;
  635.  
  636.     /*
  637.      * Make the toplevel_Wgt accessible from lisp as global *TOPLEVEL_WIDGET*.
  638.      * This code must occur after calling Wc_SHELL_Init(), and preferably after
  639.      * every WINTERP widget class initializer is called.
  640.      */
  641.     sym = xlenter("*TOPLEVEL_WIDGET*");
  642.     setvalue(sym, Wshl_WidgetID_To_WIDGETOBJ(toplevel_Wgt));
  643.  
  644.     /*
  645.      * Make XLISP, WINTERP, and MOTIF version info available within interpreter.
  646.      */
  647.     sym = xlenter("*XLISP_VERSION*");
  648.     setvalue(sym, cvfixnum((FIXTYPE) XLISP_VERSION_INT)); /* XLISP_VERSION_INT from xlisp/xlisp.h */
  649.     sym = xlenter("*XLISP_REVISION*");
  650.     setvalue(sym, cvfixnum((FIXTYPE) XLISP_REVISION_INT)); /* XLISP_REVISION_INT from xlisp/xlisp.h */
  651.     sym = xlenter("*MOTIF_VERSION*");
  652.     setvalue(sym, cvfixnum((FIXTYPE) XmVERSION)); /* XmVERSION from <Xm/Xm.h> */
  653.     sym = xlenter("*MOTIF_REVISION*");
  654.     setvalue(sym, cvfixnum((FIXTYPE) XmREVISION)); /* XmREVISION from <Xm/Xm.h> */
  655.     sym = xlenter("*WINTERP_VERSION*");
  656.     setvalue(sym, cvfixnum((FIXTYPE) WINTERP_VERSION_INT)); /* WINTERP_VERSION_INT from winterp.h */
  657.     sym = xlenter("*WINTERP_REVISION*");
  658.     setvalue(sym, cvfixnum((FIXTYPE) WINTERP_REVISION_INT)); /* WINTERP_REVISION_INT from winterp.h  */
  659.   }
  660.  
  661.   xlend(&cntxt);
  662.  
  663.   /* reset the error handler */
  664.   xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, true);
  665.  
  666.   /* open the transcript file */
  667.   if (user_prefs.lisp_transcript_file && (tfp = osaopen(user_prefs.lisp_transcript_file, "w")) == NULL) {
  668.     (void) sprintf(temptext, "error: can't open transcript file: \"%s\"",
  669.            user_prefs.lisp_transcript_file);
  670.     stdputstr(temptext);
  671.   }
  672.  
  673.   /* load file specified by resource "lispInitFile" (defaults to "initialize.lsp") */
  674.   if (setjmp(cntxt.c_jmpbuf) == 0) {
  675.     if (!xlload(user_prefs.lisp_init_file, user_prefs.enable_init_msgs, FALSE)) {
  676.       (void) sprintf(temptext,
  677.              "WINTERP warning -- couldn't load initialization file: \"%s\"\n\t\
  678. Check command-line argument \"-init_file\" or Xresource \".lispInitFile\"\n",
  679.              user_prefs.lisp_init_file);
  680.       stdputstr(temptext);
  681.     }
  682.   }
  683.  
  684.   if (user_prefs.enable_init_msgs) {
  685.  
  686. #ifdef WINTERP_WANT_INET_SERVER
  687.     if (user_prefs.enable_AF_INET_server) {
  688.       (void) printf("\nXLisp INET Domain eval-server ready for input");
  689.       if (user_prefs.service_port)
  690.     (void) printf(" on port %d .\n", user_prefs.service_port);
  691.       else
  692.     (void) printf(" using service=%s .\n", user_prefs.service_name);
  693.     }
  694. #endif                /* WINTERP_WANT_INET_SERVER */
  695.  
  696. #ifdef WINTERP_WANT_UNIX_SERVER
  697.     if (user_prefs.enable_AF_UNIX_server)
  698.       (void) printf("\nXLisp Unix Domain eval-server ready for input on socket %s .\n",
  699.             user_prefs.unix_socket_filepath);
  700. #endif                /* WINTERP_WANT_UNIX_SERVER */
  701.  
  702. #if (defined(WINTERP_WANT_INET_SERVER) && !defined(WINTERP_WANT_UNIX_SERVER))
  703.     if (user_prefs.enable_AF_INET_server)
  704.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  705. #endif
  706. #if (!defined(WINTERP_WANT_INET_SERVER) && defined(WINTERP_WANT_UNIX_SERVER))
  707.     if (user_prefs.enable_AF_UNIX_server)
  708.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  709. #endif
  710. #if (defined(WINTERP_WANT_INET_SERVER) && defined(WINTERP_WANT_UNIX_SERVER))
  711.     if ((user_prefs.enable_AF_INET_server) || (user_prefs.enable_AF_UNIX_server))
  712.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  713. #endif
  714.  
  715.     (void) printf("================================================================================\n");
  716.   }
  717.   
  718.   /* setup longjmp target for restore */
  719.   if (setjmp(top_level))
  720.     xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, true);
  721.  
  722.   read_eval_print_just_called = TRUE; /* special initial cond */
  723.   lisp_reader_hit_eof = FALSE;
  724.  
  725.   /* Process X Events and Lisp client requests forever */
  726.   for (;;) {
  727.     /* 
  728.      * We need to setup a new error return only after each time that an XLISP 
  729.      * evaluation occurs. Therefore, we check for read_eval_print_just_called 
  730.      * (which is set by Read_Eval_Print()) and then clear it once the setjmp() 
  731.      * has been done. This avoids setting up an error return for each X event
  732.      * being processed in this loop. 
  733.      */
  734.     if (read_eval_print_just_called) {
  735.       read_eval_print_just_called = FALSE;
  736.       if (lisp_reader_hit_eof) 
  737.     break;
  738.       if (setjmp(cntxt.c_jmpbuf)) { /* longjmp target for error return */
  739.     setvalue(s_evalhook, NIL);
  740.     setvalue(s_applyhook, NIL);
  741.     xltrcindent = 0;
  742.     xldebug = 0;
  743.         xlflush();        /* needed if using (read)/(read-line) from stdin */ 
  744.       }
  745.       if (user_prefs.enable_init_msgs)
  746.     stdputstr("Xlisp-Eval-Result> "); /* use this to separate results of different evaluations */
  747.       fflush(stdout); fflush(stderr); /* otherwise output won't happen while blocked in XtAppNextEvent() */
  748.     }
  749.  
  750.     /*
  751.      * XtAppNextEvent() waits for Xevents, and while it is waiting, it will
  752.      * process inputs added via XtAppAddInput() or XtAppAddWorkProc(). Lisp 
  753.      * server input will cause Read_Eval_Print() to get called, and that
  754.      * procedure sets the globals lisp_reader_hit_eof and 
  755.      * read_eval_print_just_called. Read_Eval_Print() sends a bogus 
  756.      * XAnyEvent (event.type == 0) so as to force XtAppNextEvent() to return; 
  757.      * otherwise it would only return if a lisp evaluation caused X events 
  758.      * to be generated, which means that XLISP error returns for non-X 
  759.      * evaluations wouldn't get set up properly.
  760.      *
  761.      * XtDispatchEvent() will dispatch the actions from the events gathered
  762.      * by XtAppNextEvent(). Note that XtDispatchEvent() ignores the aforementioned
  763.      * bogus events: "if (event->type == 0) return;"
  764.      */
  765.     XtAppNextEvent(app_context, &event);
  766.     XtDispatchEvent(&event);
  767.   }
  768.   wrapup();            /* this is also called if we eval expr (quit) */
  769. }
  770.  
  771.  
  772. #ifdef WINTERP_WANT_INET_SERVER
  773. /******************************************************************************
  774.  * initialize AF_INET server, returning a socket that can be listened on.
  775.  ******************************************************************************/
  776. static int Initialize_AF_INET_Server_Socket()
  777. {
  778.   int                ls;    /* socket descriptor */
  779.   struct servent    *sp;    /* pointer to service information */
  780.   struct sockaddr_in myaddr_in;    /* for local socket address */
  781.   char* portenv;
  782.  
  783.   /* clear out address structure */
  784.   memset ((char *)&myaddr_in, 0, sizeof(struct sockaddr_in));
  785.   
  786.   /* Set up address structure for the listen socket. */
  787.   myaddr_in.sin_family = AF_INET;
  788.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  789.   
  790.   /* Find the information for the server to get the needed port number. */
  791.   if (portenv = getenv(DEFAULT_INET_PORT_ENVVAR)) { /* env var for port specification */
  792.     user_prefs.service_port = (int) strtol(portenv, (char **) NULL, 0);    /* environment var overrides Xresource setting */
  793.     myaddr_in.sin_port = htons((u_short) user_prefs.service_port);
  794.   }
  795.   else if (user_prefs.service_port != NULL)
  796.     myaddr_in.sin_port = htons((u_short) user_prefs.service_port);
  797.   else {
  798.     if ((sp = getservbyname(user_prefs.service_name, "tcp")) == NULL)
  799.       xlfatal("Unable to getservbyname() for INET Domain Socket.");
  800.     myaddr_in.sin_port = sp->s_port;
  801.   }
  802.   
  803.   /* Create the listen socket. */
  804.   if ((ls = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  805.     perror(app_name);
  806.     xlfatal("Unable to create INET Domain Socket().");
  807.   }
  808.   
  809.   /* Bind the listen address to the socket. */
  810.   if (bind(ls, &myaddr_in, sizeof(struct sockaddr_in)) == -1) {
  811.     perror(app_name);
  812.     xlfatal("Unable to bind() INET Domain Socket.");
  813.   }
  814.  
  815.   /* Initiate the listen on the socket so remote users
  816.    * can connect.  The listen backlog is set to 5, which
  817.    * is the largest currently supported.
  818.    */
  819.   if (listen(ls,5) == -1) {
  820.     perror(app_name);
  821.     xlfatal("Unable to listen() on INET Domain Socket.");
  822.   }
  823.   
  824.   setpgrp();
  825.  
  826.   fcntl(ls, F_SETFD, 1);    /* set close-on-exec for the client listener socket */
  827.   
  828.   return (ls);
  829. }
  830. #endif                /* WINTERP_WANT_INET_SERVER */
  831.  
  832.  
  833. #ifdef WINTERP_WANT_UNIX_SERVER
  834. /******************************************************************************
  835.  * initialize AF_UNIX server, returning a socket that can be listened on.
  836.  * This code contributed by Victor Kan <kan@DG-RTP.DG.COM> and modified by 
  837.  * Niels Mayer.
  838.  ******************************************************************************/
  839. static int Initialize_AF_UNIX_Server_Socket()
  840. {
  841.   int ls;            /* socket descriptor */
  842.   struct sockaddr_un myaddr_un;
  843.   char* socket_path;
  844.  
  845.   memset((char *) &myaddr_un, 0, sizeof(struct sockaddr_un));
  846.   myaddr_un.sun_family = AF_UNIX;
  847.  
  848.   if (socket_path = getenv(DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR)) /* env var for port specification */
  849.     user_prefs.unix_socket_filepath = socket_path;
  850.   /* else user_prefs.unix_socket_filepath is set to DEFAULT_UNIX_SOCKET_FILEPATH value above */
  851.  
  852. #ifndef SOCKADDR_UN_MAXLEN
  853. #define SOCKADDR_UN_MAXLEN 108    /* can't find SOCKADDR_UN_MAXLEN on hpux 7.0, however "char sun_path[108];" */ 
  854. #endif
  855.   if (strlen(user_prefs.unix_socket_filepath) > (SOCKADDR_UN_MAXLEN - 1)) {
  856.     (void) fprintf(stderr, "%s: Error -- socket path %s must be shorter than %d bytes.\n",
  857.            app_name,
  858.            user_prefs.unix_socket_filepath,
  859.            SOCKADDR_UN_MAXLEN - 1);
  860.     exit(1);
  861.   }
  862.   else
  863.     strcpy(myaddr_un.sun_path, user_prefs.unix_socket_filepath);
  864.   
  865.   /*
  866.    * Create the listen socket.
  867.    */
  868.   if ((ls = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  869.     perror(app_name);
  870.     (void) sprintf(temptext, "socket() failed to create Unix Domain socket %s .\n",
  871.            user_prefs.unix_socket_filepath);
  872.     xlfatal(temptext);
  873.   }
  874.  
  875.   /*
  876.    * Bind the listen address to the socket.
  877.    */
  878.   if (bind(ls, &myaddr_un, sizeof(myaddr_un.sun_family) + strlen(myaddr_un.sun_path)) == -1) {
  879.     perror(app_name);
  880.     (void) sprintf(temptext,
  881.            "Unable to bind() Unix Domain socket \"%s\".\n\t\
  882. Note: you may need to do \"rm %s\" if a previous\n\t\
  883. %s terminated incorrectly. Alternately, another\n\t\
  884. invocation of %s may be running, in which case you need\n\t\
  885. to specify a different UnixDomain Socket file by setting\n\t\
  886. environment variable %s, or by setting\n\t\
  887. resource %s.unixSocketFilepath .\n",
  888.            user_prefs.unix_socket_filepath,
  889.            user_prefs.unix_socket_filepath,
  890.            app_name,
  891.            app_name,
  892.            DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR,
  893.            app_name);
  894.     xlfatal(temptext);
  895.   }
  896.  
  897.   /*
  898.    * Initiate the listen on the socket so remote users
  899.    * can connect.  The listen backlog is set to 5, which
  900.    * is the largest currently supported.
  901.    */
  902.   if (listen(ls,5) == -1) {
  903.     perror(app_name);
  904.     (void) sprintf(temptext, "Unable to listen() on Unix Domain socket %s .",
  905.            user_prefs.unix_socket_filepath);
  906.     xlfatal(temptext);
  907.   }
  908.   
  909.   setpgrp();
  910.  
  911.   fcntl(ls, F_SETFD, 1);    /* set close-on-exec for the client listener socket */
  912.  
  913.   return (ls);
  914. }
  915. #endif                /* WINTERP_WANT_UNIX_SERVER */
  916.  
  917.  
  918. #ifdef WINTERP_WANT_INET_SERVER
  919. /******************************************************************************
  920.  * Accept the request on client_AF_INET_listen_socket, and open a socket for
  921.  * reading, rdsock. rdsock will be closed by Read_Eval_Print().
  922.  ******************************************************************************/
  923. static int Accept_AF_INET_Server_Request(client_listen_socket)
  924.      int client_listen_socket;
  925.   int rdsock;
  926.   int addrlen = sizeof(struct sockaddr_in);
  927.   struct sockaddr_in peeraddr_in; /* for peer socket address */
  928. #ifdef hpux            
  929.   long lingerOpt = 1L;        /* NOTE: necessary while hpux-version < 8.0 (???) */
  930. #else
  931.   struct linger lingerOpt;
  932.   lingerOpt.l_onoff  = 1;
  933.   lingerOpt.l_linger = 10000;
  934. #endif
  935.  
  936.   memset((char *)&peeraddr_in, 0, sizeof(struct sockaddr_in));
  937.   if ((rdsock = accept(client_listen_socket, &peeraddr_in, &addrlen)) == -1) {
  938.     perror(app_name);
  939.     xlfatal("Unable to accept() on INET Domain Socket."); /* CLEANUP & EXIT */
  940.   }
  941.   if (setsockopt(rdsock, SOL_SOCKET, SO_LINGER, (char *) &lingerOpt,
  942. #ifdef hpux
  943.          sizeof(long)    /* NOTE: necessary while hpux-version < 8.0 (???) */
  944. #else
  945.          sizeof(struct linger)
  946. #endif
  947.          ) == -1) {
  948.     perror(app_name);
  949.     xlfatal("Unable to setsockopt() on INET Domain Socket."); /* CLEANUP & EXIT */
  950.   }
  951.  
  952.   fcntl(rdsock, F_SETFD, 1);    /* set close-on-exec for the client read socket */
  953.  
  954.   return (rdsock);
  955. }
  956. #endif                /* WINTERP_WANT_INET_SERVER */
  957.  
  958.  
  959. #ifdef WINTERP_WANT_UNIX_SERVER
  960. /******************************************************************************
  961.  * Accept the request on client_AF_UNIX_listen_socket, and open a socket for
  962.  * reading, rdsock. rdsock will be closed by Read_Eval_Print().
  963.  * This code contributed by Victor Kan <kan@DG-RTP.DG.COM> and modified by 
  964.  * Niels Mayer.
  965.  ******************************************************************************/
  966. static int Accept_AF_UNIX_Server_Request(client_listen_socket)
  967.      int client_listen_socket;
  968.   int rdsock;
  969.   struct sockaddr_un peeraddr_un;
  970.   int addrlen = sizeof (struct sockaddr_un);
  971.   memset ((char *) &peeraddr_un, 0, sizeof (struct sockaddr_un));
  972.  
  973.   if ((rdsock = accept(client_listen_socket, &peeraddr_un, &addrlen)) == -1) {
  974.     perror(app_name);
  975.     xlfatal("Unable to accept() on Unix Domain socket."); /* cleanup and exit */
  976.   }
  977.  
  978.   fcntl(rdsock, F_SETFD, 1);    /* set close-on-exec for the client read socket */
  979.  
  980.   return (rdsock);
  981. }
  982. #endif                /* WINTERP_WANT_UNIX_SERVER */
  983.  
  984.  
  985. #ifdef WINTERP_WANT_INET_SERVER
  986. /******************************************************************************
  987.  * This procedure is called (indirectly, via XtAppAddInput() callback) from 
  988.  * XtAppNextEvent() in main() and from XtAppNextEvent() in 
  989.  * xldbug.c:breakloop(). This callback will be called whenever new input 
  990.  * appears on client_AF_INET_listen_socket indicating that a new connection has been 
  991.  * requested and that another s-expression is ready to be evaluated by Xlisp. 
  992.  * This procedure will accept that connection and read all the data from the 
  993.  * client and send it off to the XLisp reader, and the Xlisp evaluator. 
  994.  * The results of the evaluation are printed.
  995.  ******************************************************************************/
  996. static void AF_INET_Read_Eval_Print(client_data, source_fildes, id)
  997.      XtPointer  client_data;
  998.      int*       source_fildes;
  999.      XtInputId* id;
  1000. {
  1001.   Read_Eval_Print(Accept_AF_INET_Server_Request(client_AF_INET_listen_socket));
  1002. }
  1003. #endif                /* WINTERP_WANT_INET_SERVER */
  1004.  
  1005. #ifdef WINTERP_WANT_UNIX_SERVER
  1006. /******************************************************************************
  1007.  * This procedure is called (indirectly, via AtAppAddInput() callback) from 
  1008.  * XtAppNextEvent() in main() and from XtAppNextEvent() in 
  1009.  * xldbug.c:breakloop(). This callback will be called whenever new input 
  1010.  * appears on client_AF_UNIX_listen_socket indicating that a new connection has been 
  1011.  * requested and that another s-expression is ready to be evaluated by Xlisp. 
  1012.  * This procedure will accept that connection and read all the data from the 
  1013.  * client and send it off to the XLisp reader, and the Xlisp evaluator. 
  1014.  * The results of the evaluation are printed.
  1015.  ******************************************************************************/
  1016. static void AF_UNIX_Read_Eval_Print(client_data, source_fildes, id)
  1017.      XtPointer  client_data;
  1018.      int*       source_fildes;
  1019.      XtInputId* id;
  1020. {
  1021.   Read_Eval_Print(Accept_AF_UNIX_Server_Request(client_AF_UNIX_listen_socket));
  1022. }
  1023. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1024.  
  1025.  
  1026. /******************************************************************************
  1027.  * This procedure is called from AF_UNIX_Read_Eval_Print() or
  1028.  * AF_INET_Read_Eval_Print(). Those procedures will accept the connections
  1029.  * requested on client_AF_UNIX_listen_socket or client_AF_INET_listen_socket
  1030.  * and return a read-socket <rdsock> from which this procedure will
  1031.  * read all the data from the client and send it off to the XLisp reader,
  1032.  * and the Xlisp evaluator.  The results of the evaluation are printed.
  1033.  ******************************************************************************/
  1034. static void Read_Eval_Print(rdsock)
  1035.      int rdsock;
  1036. {
  1037.   static char rdbuf[BUFSIZ];
  1038.   int len, i;
  1039.   LVAL sexp_stream, new_elt, last_elt = NIL;
  1040.  
  1041.   /* 
  1042.    * set this global flag so that main() and breakloop() will set up an error 
  1043.    * handler for the next call to the lisp evaluator.
  1044.    */
  1045.   read_eval_print_just_called = TRUE; 
  1046.  
  1047.   /*
  1048.    * Read the sexpression from the socket -- note assumption that entire
  1049.    * sexpression is sent in one "packet" and then the socket is closed.
  1050.    */
  1051.  
  1052.   xlsave1(sexp_stream);        /* protect from gc */
  1053.   sexp_stream = newustream();    /* note - stream obj has ptrs for head and tail*/
  1054.  
  1055.   while (len = recv(rdsock, rdbuf, BUFSIZ, 0)) { /* read len characters into rdbuf */
  1056.     if (len < 0) {
  1057.       perror(app_name);
  1058.       xlfatal("Unable to recv() on read socket."); /* CLEANUP & EXIT */
  1059.     }
  1060.  
  1061.     /* foreach character received, stuff it into an xlisp unnamed stream */
  1062.     for (i = 0; i < len; i++) {
  1063.       new_elt = cons(cvchar(rdbuf[i]), NIL);
  1064.       if (last_elt) {        /* if we've already created the head of the stream */
  1065.     rplacd(last_elt, new_elt); /* add new_elt to the tail of the list */
  1066.     last_elt = new_elt;    /* increment last_elt pointer */
  1067.       }
  1068.       else {            /* else create the head of the stream */
  1069.     sethead(sexp_stream, new_elt);
  1070.     last_elt = new_elt;
  1071.       }
  1072.     }
  1073.   }
  1074.   close(rdsock);        /* we've finished reading from the socket */
  1075.     
  1076.   if (last_elt)
  1077.     settail(sexp_stream, last_elt); /* streams are cdr-coded -- give ptr to tail */
  1078.   else            
  1079.     sexp_stream = NIL;        /* loop never executed, no characters read. */
  1080.   lisp_reader_hit_eof = !(Read_From_Stream_Eval_And_Print(sexp_stream));
  1081.   xlpop();            /*sexp_stream*/
  1082.  
  1083.  
  1084.   /* TODO -- 
  1085.      (1) make the client program, wl, wait until the evaluation is done. This will
  1086.      ensure that we don't get into a "race condition" with gnumeacs' winterp-mode --
  1087.      It is possible that winterp will still be reading winterp-mode's tempfile
  1088.      as gnuemacs writes another copy of this file. This can happen when a user
  1089.      is giving the gnuemacs winterp-send-defun command faster than winterp can
  1090.      read the files being sent to it.
  1091.      
  1092.      (2) send the results of the evaluation back to the client program wl, 
  1093.      have it print the results on stdout. Furthermore, if the form sent to
  1094.      winterp by wl results in a lisp error, wl should return a nonzero exitstatus. 
  1095.      
  1096.      This would be trivial, except that we'd want to send stdout and stderr
  1097.      back as well. If we were to use only the xlisp xlio.c routiunes for printing
  1098.      We could conceivably set the lisp symbols *standard-output* *debug-output*
  1099.      and *trace-output* so that they print to a stream, and just shove these
  1100.      streams back at the client.
  1101.      */
  1102.  
  1103.   /*
  1104.    * HACK CAUSED BY LAME IMPLEMENTATION OF XtMainLoop/XtAppNextEvent:
  1105.    * This creates a bogus event so as to force XtAppNextEvent to return, even if
  1106.    * the lisp evaluation didn't result in any new events being generated. 
  1107.    * The problem was that XtAppAddInput callbacks were being handled entirely 
  1108.    * within XtAppNextEvent(). Thus, once this procedure exited, XtAppNextEvent() 
  1109.    * would block waiting for a "real event", and never exit until an XEvent 
  1110.    * occured. XLISP requires that a new setjmp/longjmp error return be setup 
  1111.    * before each new lisp evaluation, and that couldn't happen unless 
  1112.    * XtAppNextEvent exited and allowed a new execution context to be created.
  1113.    *
  1114.    * Although I could do a call to XEventsQueued(display, QueuedAfterFlush)
  1115.    * in order to determine whether a bogus event needs to be sent, my hunch
  1116.    * is that the extra XFlush() caused by that operation would be more 
  1117.    * inefficient than processing/discarding the extra bogus event each time
  1118.    * a sexp is sent to the lisp server.
  1119.    */
  1120.   {
  1121.     XEvent bogus_event;
  1122.     bogus_event.type = 0;    /* XAnyEvent type --> ignored by XtDispatchEvent() */
  1123.     bogus_event.xany.display = display;
  1124.     bogus_event.xany.window  = XtWindow(toplevel_Wgt);;
  1125.     XPutBackEvent(display, &bogus_event);
  1126.   }
  1127. }
  1128.  
  1129.  
  1130. /*******************************************************************************
  1131.  * This fn reads from its input, which is assumed to be a xlisp stream.
  1132.  * returns false if EOF hit during read.
  1133.  ******************************************************************************/
  1134. static int Read_From_Stream_Eval_And_Print(sexp_stream)
  1135.      LVAL sexp_stream;        /* make sure this is a stream, and not other LVAL */
  1136. {
  1137.   extern int xldebug;
  1138.   extern LVAL s_1plus,s_2plus,s_3plus,s_1star,s_2star,s_3star,s_minus;
  1139.   LVAL rep_expr;
  1140.   int read_result;
  1141.  
  1142.   xlprot1(sexp_stream);        /* protect against GC */
  1143.     
  1144.   /* Read Evaluate and Print the expression in sexp_stream */
  1145.   if ((read_result = xlread(sexp_stream, &rep_expr, FALSE))) {
  1146.  
  1147.     /* save the last expression returned by the reader */
  1148.     setvalue(s_3plus, getvalue(s_2plus));
  1149.     setvalue(s_2plus, getvalue(s_1plus));
  1150.     setvalue(s_1plus, getvalue(s_minus));
  1151.     setvalue(s_minus, rep_expr);
  1152.  
  1153.     /* evaluate the expression returned by the reader */
  1154.     rep_expr = xleval(rep_expr);
  1155.  
  1156.     /* save the last expression returned by the evaluator */
  1157.     setvalue(s_3star,getvalue(s_2star));
  1158.     setvalue(s_2star,getvalue(s_1star));
  1159.     setvalue(s_1star,rep_expr);
  1160.  
  1161.     if (xldebug)        /* print eval results */
  1162.       dbgprint(rep_expr);
  1163.     else
  1164.       stdprint(rep_expr);
  1165.   }
  1166.  
  1167.   else {            /* if reader hit EOF, just print a new line */
  1168.     if (xldebug)
  1169.       dbgputstr("\n");   
  1170.     else
  1171.       stdputstr("\n");
  1172.   }
  1173.   xlpop(/*sexp_stream*/);
  1174.   return (read_result);        /* return FALSE if hit EOF */
  1175. }
  1176.  
  1177.  
  1178. /*******************************************************************************
  1179.  * xlfatal - print a fatal error message and exit
  1180.  ******************************************************************************/
  1181. xlfatal(msg)
  1182.   char *msg;
  1183. {
  1184.   extern FILE *tfp;
  1185.  
  1186.   (void) fprintf(stderr, "%s -- error: %s\n", app_name, msg);
  1187.  
  1188. #ifdef WINTERP_WANT_INET_SERVER
  1189.   if (client_AF_INET_listen_socket)
  1190.     close(client_AF_INET_listen_socket);
  1191. #endif                /* WINTERP_WANT_INET_SERVER */
  1192.  
  1193. #ifdef WINTERP_WANT_UNIX_SERVER
  1194.   if (client_AF_UNIX_listen_socket) {
  1195.     close(client_AF_UNIX_listen_socket);
  1196.     unlink(user_prefs.unix_socket_filepath);
  1197.   }
  1198. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1199.  
  1200.   if (tfp)
  1201.     fclose(tfp);
  1202.  
  1203.   if (app_context)
  1204.     XtDestroyApplicationContext(app_context);
  1205.  
  1206.   exit(1);
  1207. }
  1208.  
  1209.  
  1210. /*******************************************************************************
  1211.  * wrapup - clean up and exit to the operating system. 
  1212.  * This is also called in xlsys.c:xexit().
  1213.  ******************************************************************************/
  1214. wrapup()
  1215. {
  1216.   extern FILE *tfp;
  1217.  
  1218.   stdputstr("\n");
  1219.  
  1220. #ifdef WINTERP_WANT_INET_SERVER
  1221.   if (client_AF_INET_listen_socket)
  1222.     close(client_AF_INET_listen_socket);
  1223. #endif                /* WINTERP_WANT_INET_SERVER */
  1224.  
  1225. #ifdef WINTERP_WANT_UNIX_SERVER
  1226.   if (client_AF_UNIX_listen_socket) {
  1227.     close(client_AF_UNIX_listen_socket);
  1228.     unlink(user_prefs.unix_socket_filepath);
  1229.   }
  1230. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1231.  
  1232.   if (tfp)
  1233.     fclose(tfp);
  1234.  
  1235.   if (app_context)
  1236.     XtDestroyApplicationContext(app_context);
  1237.  
  1238.   exit(0);
  1239. }
  1240.  
  1241. /*******************************************************************************
  1242.  * This is the protocol callback for application shells created in WINTERP.
  1243.  * see toplevel_Wgt above, and also APPLICATION_SHELL_WIDGET_CLASS in
  1244.  * wc_SHELL.c.
  1245.  ******************************************************************************/
  1246. void Winterp_Application_Shell_WMDelete_Callback(shell, closure, call_data)
  1247.      Widget shell;
  1248.      XtPointer closure;
  1249.      XtPointer call_data;
  1250. {
  1251.   wrapup();
  1252. }
  1253.  
  1254. /*******************************************************************************
  1255.  * This handles fatal errors from the Xtoolkit. According to the Xtoolkit
  1256.  * docs, such a handler should terminate the application. In this case,
  1257.  * however, we suggest to the user that the application be terminated, but
  1258.  * don't actually do it. This may allow the user to figure out what went 
  1259.  * wrong by poking around inside the lisp environment.
  1260.  *
  1261.  * This is set up in main() via XtAppSetErrorHandler(). Note that the default
  1262.  * error handler is _XtDefaultError().
  1263.  ******************************************************************************/
  1264. static void Winterp_Xtoolkit_Error_Handler(message)
  1265.      String message;
  1266. {
  1267.   (void) sprintf(temptext,
  1268.          "X Toolkit Fatal Error -- PLEASE QUIT AND RESTART THIS APPLICATION:\n\t%s\n",
  1269.          message);
  1270.   xlfail(temptext);
  1271. }
  1272.  
  1273.  
  1274. /*******************************************************************************
  1275.  * This handles nonfatal errors from the Xtoolkit.
  1276.  *
  1277.  * This is set up in main() via XtAppSetWarningHandler(). Note that the default
  1278.  * error handler is _XtDefaultWarning().
  1279.  ******************************************************************************/
  1280. static void Winterp_Xtoolkit_Warning_Handler(message)
  1281.      String message;
  1282. {
  1283.   (void) sprintf(temptext,
  1284.          "X Toolkit Warning:\n\t%s\n",
  1285.          message);
  1286.   xlfail(temptext);
  1287. }
  1288.  
  1289.  
  1290. /*******************************************************************************
  1291.  * The following code is from X11r4:mit/lib/X/XlibInt.c.
  1292.  * Copyright    Massachusetts Institute of Technology    1985, 1986, 1987.
  1293.  ******************************************************************************/
  1294. static int Winterp_XPrintDefaultError (dpy, event, fp)
  1295.     Display *dpy;
  1296.     XErrorEvent *event;
  1297.     FILE *fp;
  1298. {
  1299.     char buffer[BUFSIZ];
  1300.     char mesg[BUFSIZ];
  1301.     char number[32];
  1302.     char *mtype = "XlibMessage";
  1303.     register _XExtension *ext = (_XExtension *)NULL;
  1304.     XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
  1305.     XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
  1306.     (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
  1307.     XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", 
  1308.     mesg, BUFSIZ);
  1309.     (void) fprintf(fp, mesg, event->request_code);
  1310.     if (event->request_code < 128) {
  1311.     sprintf(number, "%d", event->request_code);
  1312.     XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
  1313.     } else {
  1314.     for (ext = dpy->ext_procs;
  1315.          ext && (ext->codes.major_opcode != event->request_code);
  1316.          ext = ext->next)
  1317.       ;
  1318.     if (ext)
  1319.         strcpy(buffer, ext->name);
  1320.     else
  1321.         buffer[0] = '\0';
  1322.     }
  1323.     (void) fprintf(fp, " (%s)\n  ", buffer);
  1324.     XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
  1325.     mesg, BUFSIZ);
  1326.     (void) fprintf(fp, mesg, event->minor_code);
  1327.     if (ext) {
  1328.     sprintf(mesg, "%s.%d", ext->name, event->minor_code);
  1329.     XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
  1330.     (void) fprintf(fp, " (%s)", buffer);
  1331.     }
  1332.     fputs("\n  ", fp);
  1333.     XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
  1334.     mesg, BUFSIZ);
  1335.     (void) fprintf(fp, mesg, event->resourceid);
  1336.     fputs("\n  ", fp);
  1337.     XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", 
  1338.     mesg, BUFSIZ);
  1339.     (void) fprintf(fp, mesg, event->serial);
  1340.     fputs("\n  ", fp);
  1341.     XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
  1342.     mesg, BUFSIZ);
  1343.     (void) fprintf(fp, mesg, dpy->request);
  1344.     fputs("\n", fp);
  1345.     if (event->error_code == BadImplementation) return 0;
  1346.     return 1;
  1347. }
  1348.  
  1349.  
  1350. /*******************************************************************************
  1351.  * This handles errors from Xlib. It is set up in main() via XSetErrorHandler().
  1352.  *
  1353.  * By default, the Xlib error handler is:
  1354.  *
  1355.  * int _XDefaultError(dpy, event)
  1356.  *     Display *dpy;
  1357.  *     XErrorEvent *event;
  1358.  * {
  1359.  *     if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
  1360.  *     exit(1);
  1361.  * }
  1362.  *
  1363.  * However for WINTERP, we don't want to have exit() called on such errors,
  1364.  * rather we call xlfail() to indicate an error occured and to throw us into
  1365.  * the debug loop.
  1366.  ******************************************************************************/
  1367. static int Winterp_Xlib_Error_Handler(dpy, event)
  1368.      Display*     dpy;
  1369.      XErrorEvent* event;
  1370. {
  1371.  
  1372.   (void) Winterp_XPrintDefaultError (dpy, event, stderr);
  1373.   xlfail("Xlib error detected.");
  1374.   return (0);
  1375. }
  1376.